package com.univrz.flexmachine.scxml.model
{
	
	
	import flash.events.Event;
	import flash.utils.Dictionary;




	/**
	 * 
	 * 
	 * 
	 * 
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class TransitionEdge extends SCXMLModelObject
	{
		


		//////////////////////////////////////////
		// event
		//////////////////////////////////////////

		public var event:String;
		
		

		//////////////////////////////////////////
		// cond
		//////////////////////////////////////////

		private var _cond:Boolean;

		/**
		 * 
		 * This is the only property that can be changed on runtime,
		 * to indicate a dynamic change on the condition
		 * 
		 * @return 
		 * 
		 */
		public function get cond( ):Boolean
		{
			return _cond;
		}
		public function set cond( v:Boolean ):void
		{
			if ( _cond == v )
				return;
			_cond = v;
			update( );
		}
		
		



		//////////////////////////////////////////
		// targets
		//////////////////////////////////////////

		public var targets:Array;



		//////////////////////////////////////////
		// source
		//////////////////////////////////////////

		public var source:Node;





		//////////////////////////////////////////
		// content
		//////////////////////////////////////////

		public var content:*;





		//////////////////////////////////////////
		// canFire
		//////////////////////////////////////////

		private var _canFire:Boolean;
		[Bindable("change")]
		/**
		 * 
		 * This property is true when the source state is active AND our condition is set to true.
		 * The engine uses this to preselect transitions before matching events
		 * 
		 * @return 
		 * 
		 */		
		public function get canFire( ):Boolean
		{
			return _canFire;
		}




		
		
		
		
		
		public function TransitionEdge( source:Node, cond:Boolean=true, event:String=null, targets:Array=null, content:*=null )
		{
			this.source 	= source;
			this._cond		= cond;
			this.event 		= event;
			this.targets 	= targets;
			this.content	= content;
			
			source.addEventListener( Event.CHANGE, source_change );
			
			
			// store in cache
			
			if ( !cache[source] )
				cache[source] = [];
			cache[ source ].push( this );
		
		}



		
		private function update( ):void
		{
			var t:Boolean = ( source.isActive && cond ); 
			if ( _canFire == t )
				return;
			_canFire = t;
			dispatchEvent( new Event( Event.CHANGE ) );
		}




		private function source_change( event:Event ):void
		{
			update( );		
		}




		/**
		 * 
		 * Perform name based comparison according to rules
		 * TODO: take into account (.*) rules
		 * 
		 * If our event is null and you pass null, result = true
		 * 
		 * @param event
		 * @return 
		 * 
		 */
		internal function matchesEvent( event:String ):Boolean
		{
			return ( this.event == event );			
		}
		
		
		
		
		
		
		private var $sourceAndTargetsLCA:* = undefined;

		/**
		 * 
		 * Returns the LCA of the source and targets together
		 * 
		 * @return 
		 * 
		 */		
		internal function get sourceAndTargetsLCA( ):Node
		{
			if ( $sourceAndTargetsLCA === undefined )
				$sourceAndTargetsLCA = Node.findLCA( [ this.source ].append( this.targets ) );
			return $sourceAndTargetsLCA as Node;
		}



		///////////////////////////////////////////////////////////
		// static registry. transitions are edges, we store them here by source
		///////////////////////////////////////////////////////////


		private static var cache:Dictionary = new Dictionary( true );
		
		public static function forSource( source:Node ):Array
		{
			if ( cache[ source ] )
				return cache[ source ];
			return [ ];
		}			
		
		

	}
	
}